using System;
using System.Threading;
using Cysharp.Threading.Tasks;
using GameFramework.Reference;
using GameFramework.Request;

namespace GameFramework.Rpc
{
    internal partial class RpcServiceImpl
    {
        private sealed class RpcWaiter : AReference, IRpcWaiter, IDisposable
        {
            public uint RpcId { get; set; }
            public Action<RpcWaiter> OnDisposeAction { get; set; }

            private IResponse m_Response;
            
            public async UniTask<IResponse> GetResponseAsync(CancellationToken token)
            {
                bool isDone() => m_Response != null;
                await UniTask.WaitUntil(isDone, cancellationToken: token).SuppressCancellationThrow();
                
                var response = m_Response;
                m_Response = null;

                response ??= ReferenceService.GetReference<CommonResponse>().SetErrorCode(GameFrameworkErrorCode.RequestHasBeenCanceled);
                Dispose();
                
                return response;
            }

            public void Dispose()
            {
                OnDisposeAction?.Invoke(this);
            }

            public void SetResponse(IResponse response)
            {
                if (m_Response != null)
                {
                    response.Recycle();
                    return;
                }
                
                m_Response = response;
            }
            
            public override void OnRecycle()
            {
                RpcId = 0;
                OnDisposeAction = null;
                m_Response = null;
            }
        }
    }
}